package com.demo.zk;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import org.junit.Before;
import org.junit.Test;

import java.util.List;

/**
 * @author Jerry.Zeng
 * @version v1.0.0
 * @date 2021/9/22 15:37
 */
public class zkClient {

    /** 连接客户端 */
    private static final String connectString = "localhost:2181";
    /** 超时时间 */
    private static final int sessionTimeout = 2000;
    /** 客户端 */
    private ZooKeeper zkClient = null;

    /**
     * 创建客户端
     */
    @Before
    public void init() throws Exception {
        zkClient = new ZooKeeper(
                // 客户端地址
                connectString,
                // 超时时间
                sessionTimeout,
                // 创建监听器 - 连接成功后执行的步骤
                new Watcher() {
                    @Override
                    public void process(WatchedEvent watchedEvent) {
                        // 收到事件通知后的回调函数（用户的业务逻辑）
                        System.out.println(watchedEvent.getType() + "--" + watchedEvent.getPath());
                        // 再次启动监听
                        try {
                            // 再次开启一次监听，于是乎就相当于递归
                            List<String> children = zkClient.getChildren("/", true);
                            for (String child : children) {
                                System.out.println(child);
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                });
    }

    /**
     * 创建子节点
     */
    @Test
    public void create() throws Exception {
        // 参数1：要创建的节点的路径；参数2：节点数据；参数3：节点权限；参数4：节点的类型
        String nodeCreated = zkClient.create(
                // 参数1：要创建的节点的路径
                "/atguigu",
                // 参数2：节点数据
                "shuaige".getBytes(),
                // 参数3：节点权限 - 任何人都可以进行访问
                ZooDefs.Ids.OPEN_ACL_UNSAFE,
                // 参数4：节点的类型(持久、序号) -e -s
                CreateMode.PERSISTENT
        );
    }

    /**
     * 就是设置一个路径，进行遍历，如果数据有变化，则执行监听方法。
     * 然后监听方法再执行这个方法，其实就相当于进行递归执行，达到监听效果。
     * 返回给定路径的节点的子节点列表
     * 监听方法就是getChildren，传递监听路径和监听方法
     * 监听方法如果设置为true则走创建客户端的时候创建的监听器，当然也可以创建自己的监听器
     * 获取子节点 - 目的是为了监听节点变化
     *
     * 总结：zkClient.getChildren方法就是监听方法，但是只是监听一次
     * 因此：执行方法后会执行监听器方法，需要在监听器方法继续调用该方法，类似递归调用。这样就可以实现持续监听。
     */
    @Test
    public void getChildren() throws Exception {
        // 启动监听，设置为true，默认走上面创建客户端的监听器
        List<String> children = zkClient.getChildren("/", true);
//        for (String child : children) {
//            System.out.println(child);
//        }
        // 延时阻塞
        Thread.sleep(Long.MAX_VALUE);
    }

    /**
     * 判断znode是否存在
     */
    @Test
    public void exist() throws Exception {
        Stat stat = zkClient.exists("/atguigu", false);
        System.out.println(stat == null ? "not exist" : "exist");
    }

}

